package  de.cube3d.blitwit.space
{
	import flash.display.BitmapData;
	import flash.geom.Rectangle;
	import de.cube3d.blitwit.render.BlitSpriteScene;
	
	/**
	 * This class represents a component that can be stored and sorted efficiently in 
	 * spaces.
	 */
	public class SpaceObject
	{
		public var owner:Space;
		private static var _idcnt:int = 0;
		private var _id:int = _idcnt++;
		
		protected var _currentRect:Rectangle = new Rectangle();
		private var _sortIndex:Number = 0;
		private var _fillcolor:uint = 0xff00ff;
		
		/**
		 * Flag that indicates if the object is animated. If it is 
		 * false (default), it will not receive animationTick method calls.
		 */
		public var isAnimated:Boolean; 
		
		public function set x (x:Number):void {
			setPos(x, _currentRect.y);
		}
		
		public function set y (y:Number):void {
			setPos(_currentRect.x, y);
		}
		
		public function setPos (x:Number, y:Number):SpaceObject {
			var oldx:Number = _currentRect.x;
			var oldy:Number = _currentRect.y;
			_currentRect.x = x;
			_currentRect.y = y;
			if (owner) {
				owner.objectMoved(this, oldx, oldy, _currentRect.x, _currentRect.y);
			}
			return this;
		}
		
		public function get x ():Number {
			return _currentRect.x;
		}
		
		public function get y():Number {
			return _currentRect.y;
		}
		
		public function get width():Number {
			return _currentRect.width;
		}
		
		public function get height():Number {
			return _currentRect.height;
		}
		
		public function setFillColor(col:uint):SpaceObject {
			_fillcolor = col;
			return this;
		}
		
		public function SpaceObject(x:Number, y:Number, width:Number, height:Number) 
		{
			_currentRect.x = x;
			_currentRect.y = y;
			_currentRect.width = width;
			_currentRect.height = height;
		}
		
		public function set sortIndex(idx:Number):void {
			setSortIndex(idx);
		}
		
		public function get sortIndex():Number {
			return _sortIndex;
		}
		
		public function get uid():int {
			return _id;
		}
		
		public function setSortIndex(idx:Number):SpaceObject {
			if (_sortIndex == idx) return this;
			if (owner) owner.sortIndexChanged(this, _sortIndex, idx);
			_sortIndex = idx;
			return this;
		}
		
		/**
		 * This function should be overridden by child classes that put more sense into it.
		 * Just respect the clipping rectangle under all circumstances.
		 * @param	bm			the target bitmapdata object to draw onto
		 * @param	x			x coordinate on the bitmap to draw your stuff
		 * @param	y			y coordinate on the bitmap to draw your stuff
		 * @param	scale		Scaling factor for the drawing. You're in charge to handle 
		 * 						this efficently. Just draw you'r stuff at x,y and scale it.
		 * @param	clipRect 	Clipped area on the bitmap area that MUST be followed. Don't 
		 * 						blame me for the fun you'll have when not respecting it.
		 */
		public function draw (bm:BitmapData, x:Number, y:Number, scale:Number, clipRect:Rectangle):void {
			var r:Rectangle;
			r = clipRect.intersection(new Rectangle(x, y, _currentRect.width, _currentRect.height));
			bm.fillRect(r, _fillcolor);
		}
		
		/**
		 * This function may be overridden if the child class needs animation support. 
		 * The scene object calls this function on all objects that are visible.
		 * The object itself is responsible for marking areas on the scene as dirty if 
		 * a repaint is required due to animation progress. 
		 * 
		 * You'll also need to set the "isAnimated" property to true, otherwise, this method
		 * will never be called.
		 * 
		 * @param	scene 	The scene to be used for marking changed areas (smaller is better)
		 * @param	t		The time parameter, given from the caller of the animationtick in the scene
		 * @param	data	A data object that can be passed from outside for further information.
		 */
		public function animationTick (scene:BlitSpriteScene, t:Number, data:*):void {
			
		}
		
		public function isContained(r:Rectangle):Boolean {
			return r.containsRect(_currentRect);
		}
		
		public function intersects(r:Rectangle):Boolean {
			return _currentRect.intersects(r);
		}
		
		/**
		 * Should return a raw copy of this object. The copy is not required to be inserted into the 
		 * space the original is in but is required to be of the same type and have the same appearance.
		 * The intention of this function is to allow spaces to instanciate copies of spaces at will so
		 * the space can generate new content.
		 * 
		 * @param	overwrite an instance of the same class that may be used as copy target 
		 * 						The intention is to avoid garbage production by reusing objects.
		 * @return a copy of the object that has the same appearance
		 */
		public function getCopy(overwrite:SpaceObject = null):SpaceObject {
			if (overwrite == null)
				return new SpaceObject(x, y, width, height).setFillColor(_fillcolor).setSortIndex(_sortIndex);
			overwrite._currentRect.x = _currentRect.x;
			overwrite._currentRect.y = _currentRect.y;
			overwrite._currentRect.width = _currentRect.width;
			overwrite._currentRect.height = _currentRect.height;
			overwrite._fillcolor = _fillcolor;
			overwrite.sortIndex = _sortIndex;
			// don't copy the id, it is used to differenciate objects from each other (it shouldn't be a perfect copy)
			return overwrite;
		}
		
		/**
		 * If a point request is made, this function is called to check if the coordinate
		 * is part of the object. This implementation checks the point only against the
		 * rectangle area of this object.
		 * 
		 * @param	x
		 * @param	y
		 * @return true if the point is a member of the object
		 */
		public function contains(x:Number, y:Number):Boolean {
			return _currentRect.contains(x, y);
		}
	}

}